package com.example.spring5.AOP;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class AOP动态代理 {
    public static void main(String[] args) {
        /**
         * Spring AOP就是基于动态代理的，
         * 如果要代理的对象，实现了某个接口，那么Spring AOP会使用JDK Proxy，
         *          创建实现类实现代理
         * 去创建代理对象，而对于没有实现接口的对象，就无法使用 JDK Proxy 去进行代理了，
         *      这时候Spring AOP会使用Cglib ，
         *      这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理。
         *          创建对象的子类实现代理
         *
         * 方法有三个参数：
         * 第一参数，类加载器
         * 第二参数，增强方法所在的类，这个类实现的接口，支持多个接口
         * 第三参数，实现这个接口 InvocationHandler，创建代理对象，写增强的部分
         *
         */
        //JDK的动态代理
        Server server = new Server();//被代理类
        NetWork netWork = (NetWork) ProxyFactory.getProxyInstance(server);//代理类
        netWork.browse("张蛟龙");
    }
}

interface NetWork{
    public void browse(String s);
}

class Server implements NetWork{

    @Override
    public void browse(String s) {
        System.out.println("真实的服务器访问网络"+s);
    }
}//被代理类

class  ProxyFactory{

    public static Object getProxyInstance(Object obj){//被代理类对象
        MyInvocationHandler handler = new MyInvocationHandler();
        handler.bind(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),//取得该Class对象的类装载器
                obj.getClass().getInterfaces()/*获得obj的接口*/,handler);
    }
}


class MyInvocationHandler implements InvocationHandler {
    private Object obj;//需要使用被代理类的对象进行赋值
    public void bind(Object obj){
        this.obj = obj;
    }

    //当我们通过代理类的对象，调用方法a时，就会自动的调用如下的方法：invoke()
    //将被代理类要执行的方法a的功能就声明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Utils utils = new Utils();

        utils.method1();
        method.getName();//返回执行方法的名字
        //method:即为代理类对象调用的方法，此方法也就作为了被代理类对象要调用的方法
        //obj:被代理类的对象
        Object invoke = method.invoke(obj, args);
        //上述方法的返回值就作为当前类中的invoke()的返回值。


        utils.method2();
        return invoke;
    }
} //再次升级版

class Utils{
    public void method1(){
        System.out.println("====通用方法01================");
    }
    public void method2(){
        System.out.println("====通用方法02================");
    }
}